#!/bin/bash

usage() {
    (( $# > 0 )) && echo -e "$@"
    echo "
Creates a Supertuxkart Grand Prix

Without options:
Create a randomized Grand Prix of ALL tracks (both addon and builtin).

Dates and times refer to file timestamps, i.e. when the track
was locally installed, not when it was first published.

Dependencies: xml (xmlstarlet) and coreutils.

    -d int  Pick tracks from the latest int days
    -n int  Choose the newest int tracks.
            A negative number means oldest int tracks

    Options -d and -n refer to the installation date and also includes manually
    installed tracks. They also cannot be combined.

    -R      Do NOT randomize chosen tracks
            (undefined result - most likely alphabetical)
    -g str  A comma-separated list of groups to include.
            Defaults to \"$groups\"
    -a      Pick only addon tracks
    -b      Pick only bultin tracks
    -p str  Use a prefix other than $prefix

    Options -a and -b cannot be combined.
    If not specified, the default is to pick from all tracks."
    exit 1
}
is_valid() {
    local track="$dir/$1/track.xml"
    [ -r "$track" ] \
    && ! [[ "$(xml sel -t -v '//@internal' "$track")" == Y ]] \
    && ! [[ "$(xml sel -t -v '//@soccer' "$track")" == Y ]] \
    && ! [[ "$(xml sel -t -v '//@arena' "$track")" == Y ]]
}
is_latest() {
    # $1 is the directory of the track
    [[ "$days" == all ]] && return 0
    local file_time="$(get_time "$1")"
    if ((file_time >= latest_time)); then
        echo "$(date -d @$file_time) - $1"
        return 0
    else
        return 1
    fi
}
is_groups() {
    local track="$dir/$1/track.xml"
    for group in ${groups//,/ }; do
        [[ "$(xml sel -t -v '//@groups' "$track")" == *"$group"* ]] && return 0
    done
    return 1
}
get_tracks() {
    # $1 is the prefix "addon_", or nothing
    cd "$dir" || usage "Cannot cd to $dir"
    for i in *; do
        is_valid "$i" && is_groups "$i" && is_latest "$i" && grow_array "$i" "$1"
    done
}
grow_array() {
    # $1 is the directory of the track
    # $2 is the prefix "addon_", or nothing
    local x i="$2$1"
    x="$(xml sel -t -v '//@default-number-of-laps' "$dir/$1/track.xml")" || x=3
    i="<track id=\"$i\" laps=\"$x\" reverse=\"false\" />"
    ((number!=0)) && array=( "${array[@]}" "$(get_time "$1") $i" ) || array=( "${array[@]}" "$i" )
}
get_time() {
    # $1 is the directory of the track

    # accumulate all possible file times
    local file_times=() file i file_time=0
    for file in scene graph quad materials track; do
        file="$dir/$1/$file.xml"
        # stat gives more choice than 'date -r', 3 different file times in seconds since epoch
        [ -r "$file" ] && file_times=( ${filetimes[@]} $(stat --printf '%W %Y %Z' "$file") )
    done
    # we simply choose the _newest_ file time
    # this also applies if we use choose oldest tracks
    for i in ${file_times[@]}; do
        (( i > file_time )) && file_time="$i"
    done
    echo "$file_time"
}
echo_array() {
    if ((number!=0)); then
        IFS=$'\n'
        ((number>0)) && array=($(sort -nr <<<"${array[*]}")) || array=($(sort -n <<<"${array[*]}"))
        unset IFS
        for ((i=0;i<${number#-};i++)); do
            echo "${array[i]#* }"
        done
    else
        for ((i=0;i<${#array[@]};i++)); do
            echo "${array[i]}"
        done
    fi
}
# dependency checks
for dep in xml date; do
    type -f $dep >/dev/null || usage
done

# default values
addons=1
builtins=1
days=all
random=1
number=0
oldest=0
prefix=/usr/share
groups=standard,Add-Ons
re='^[+-]?[1-9][0-9]*$'
homedir="$HOME/.local/share/supertuxkart"
[ -w "$homedir/grandprix" ] || usage "Cannot access $homedir/grandprix for writing - does it exist?"

while getopts "d:n:p:Rabg:h" option; do
    case "$option" in
    d)
        [[ "$number" != 0 ]] && usage "You cannot use both -d and -n"
        # regex that means positive integer but not 0
        [[ "$OPTARG" =~ ^[1-9][0-9]*$ ]] || usage "Not a valid number: $OPTARG"
        days="$OPTARG"
        latest_time="$(date -d "now - $days days" +%s)"
    ;;
    n)
        [[ "$days" != all ]] && usage "You cannot use both -n and -d"
        # regex that means positive or negative integer but not 0
        [[ "$OPTARG" =~ ^[+-]?[1-9][0-9]*$ ]] || usage "Not a valid number: $OPTARG"
        number="$OPTARG"
    ;;
    p)
        prefix="$OPTARG"
        [ -d "$prefix" ] || usage "The prefix $prefix is not a directory on this machine."
    ;;
    R)
        random=0
    ;;
    a)
        builtins=0
        [[ "$addons" == 0 ]] && usage "You cannot use both -a and -b"
    ;;
    b)
        addons=0
        [[ "$builtins" == 0 ]] && usage "You cannot use both -a and -b"
    ;;
    g)
        groups="$OPTARG"
    ;;
    h|*)
        usage
    ;;
    esac
done

# optional dependency checks
if [[ "$random" == 1 ]]; then
    type -f shuf >/dev/null || usage
fi
if [[ "$days" != all ]]; then
    type -f stat >/dev/null || usage
fi

prompt="Creating"
[[ "$random" == 0 ]] && prompt="$prompt non-randomized"
prompt="$prompt GrandPrix with"
if [[ "$number" == 0 ]]; then
    [[ "$days" == all ]] && prompt="$prompt tracks from any date" || prompt="$prompt tracks updated during the last $days days"
else
    ((number<0)) && prompt="$prompt ${number#-} oldest tracks" || prompt="$prompt $number newest tracks"
fi
[[ "$builtins" == 0 ]] && prompt="$prompt (add-ons only)"
[[ "$addons" == 0 ]] && prompt="$prompt (built-ins only)"
[[ "$groups" != "standard,Add-Ons" ]] && prompt="${prompt}, groups: $groups"
echo "${prompt}."
read -p "Proceed (Enter/Ctrl-c)? "

file="$homedir/grandprix/usr_gp_$(date +'%Y%m%d-%H%M%S').grandprix"
[ -e "$file" ] && usage "Filename\n$file\nalready exists - how weird is that!"

array=()

if [[ "$builtins" == 1 ]]; then
    dir="$prefix/supertuxkart/data/tracks"
    get_tracks
fi

if [[ "$addons" == 1 ]]; then
    dir="$homedir/addons/tracks"
    get_tracks "addon_"
fi

if (( ${#array[@]} > 0 )); then
    name="tracks ($(date '+%b %-d'))"
    #~ [[ "$days" != all ]] && name="tracks last ${days}d $name"
    [[ "$addons" == 0 ]] && name="built-in $name"
    [[ "$builtins" == 0 ]] && name="add-on $name"
    #~ [[ "$random" == 1 ]] && name="random $name"
    ((number<0)) && name="oldest $name"
    ((number!=0)) && name="${number#-} $name" || name="${#array[@]} $name"
    start="\n<supertuxkart_grand_prix name=\"$name\">\n"
    end="\n</supertuxkart_grand_prix>\n"
    {
    echo -e "$start"
    if [[ "$random" == 0 ]]; then
        echo_array
    else
        echo_array | shuf
    fi
    echo -e "$end"
    } > "$file"
    echo -e "\nGenerated GrandPrix \"$name\"\nSaved to ~${file#$HOME}"
else
    echo "No tracks, no GrandPrix!"
    exit 1
fi
